package com.fadadianqi.goods.service;

import com.fadadianqi.cache.Cache;
import com.fadadianqi.cache.CacheFactory;
import com.fadadianqi.commons.JSONProvider;
import com.fadadianqi.commons.PrimaryKeyCreator;
import com.fadadianqi.exception.DuplicateException;
import com.fadadianqi.goods.dao.*;
import com.fadadianqi.goods.model.*;
import com.fadadianqi.goods.model.Properties;
import com.fadadianqi.search.IndexObjectBufferPool;
import com.yeqiangwei.commons.util.Pagination;
import com.yeqiangwei.commons.util.StringHelper;
import com.yeqiangwei.commons.util.ValidatorHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class GoodsService {

    private static final Log log = LogFactory.getLog(GoodsService.class);

    private Cache cache = CacheFactory.getDefault();


    /**
     * 添加/更新分类属性
     *
     * @param properties
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void saveProperties(Properties properties) throws Exception {
        if (ValidatorHelper.isEmpty(properties.getCategoryId())) {
            throw new Exception("exception.required.categoryId");
        } else if (ValidatorHelper.isEmpty(properties.getName())) {
            throw new Exception("exception.required.name");
        }
        if (ValidatorHelper.isEmpty(properties.getId())) {
            properties.setId(PrimaryKeyCreator.create());
            if (propertiesDAO.getByCategoryIdAndName(properties.getCategoryId(), properties.getName()) == null) {
                propertiesDAO.create(properties);
            } else {
                // 有重复的属性
                throw new DuplicateException("exception.duplicate.name");
            }
        } else {
            propertiesDAO.update(properties);
        }
    }

    public void delProperties(Properties props) {
        propValueDAO.removeByPropId(props.getId());
        propertiesDAO.remove(props);
    }

    public Properties getProperties(String propId) {
        return propertiesDAO.getById(propId);
    }

    public List<Properties> findPropsByCategoryId(String id) {
        return propertiesDAO.findByCategoryId(id);
    }

    public List<Properties> findPropsByCategory(Category c) {
        return findPropsByCategoryId(c.getId());
    }

    /**
     * 判断是否有重复的商品存在
     * 1,检查同商品同分类下是否有同名商品，是则继续第二部，否则返回FALSE。
     *
     * @param goods
     * @param uniqueName
     * @return
     */
    private boolean isDuplicate(Goods goods, String uniqueName) {
        String brandId = goods.getBrandId();
        String categoryId = goods.getCategoryId();
        Goods ug = goodsDAO.getByUniqueNameAndBrandIdAndCategoryId(uniqueName, brandId, categoryId);
        if (ug != null && (goods.getId() == null || !goods.getId().equalsIgnoreCase(ug.getId()))) {
            return Boolean.TRUE;
        } else {
            return Boolean.FALSE;
        }
    }


    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void updateGoodsTimeUtils(Goods goods) {
        goodsDAO.update(goods);
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void saveGoods(Goods goods) throws Exception {
        saveGoods(goods, null);

    }

    public List<BrandCategoryRelation> findRelationBrand(String cid) {
        return brandCategoryRelationDAO.findByCategoryId(cid);
    }

    public List<BrandCategoryRelation> findRelationCategory(String bid) {
        return brandCategoryRelationDAO.findByBrandId(bid);
    }

    /**
     * 此方法升级时使用，且仅使用一次
     */
    private void initBrandCategoryRelation() {
        Pagination pagination = new Pagination(1, Integer.MAX_VALUE);
        List<BrandCategoryRelation> bcrList = brandCategoryRelationDAO.findAll(pagination);
        if(ValidatorHelper.isNotEmpty(bcrList)) {
            return;
        }
        List<Goods> list = this.findAllGoods(pagination);
        if(ValidatorHelper.isEmpty(list)){
            return ;
        }
        for(Goods goods : list) {
            String bid = goods.getBrandId();
            String cid = goods.getCategoryId();
            BrandCategoryRelation bcr = brandCategoryRelationDAO.getByBrandIdAndCategoryId(bid, cid);
            if(null == bcr) {
                bcr = new BrandCategoryRelation();
                bcr.setId(PrimaryKeyCreator.create());
                bcr.setCategoryId(cid);
                bcr.setBrandId(bid);
                brandCategoryRelationDAO.create(bcr);
            }
        }
    }

    /**
     * @param goods
     * @throws Exception
     */
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void saveGoods(Goods goods, String props) throws Exception {

        // 升级调用的方法，系统真正使用时不用此初始化方法
        initBrandCategoryRelation();

        StringBuilder uniqueName = new StringBuilder();
        uniqueName.append(goods.getName());
        Map<String, String> propMap = null;
        if (ValidatorHelper.isNotEmpty(props)) {
            propMap = (Map<String, String>) JSONProvider.toBean(props, HashMap.class);
            Set<String> keys = propMap.keySet();
            Iterator<String> keyIterator = keys.iterator();
            while (keyIterator.hasNext()) {
                String propId = keyIterator.next();
                String valId = propMap.get(propId);
                uniqueName.append(",");
                uniqueName.append(valId);
            }
        }
        if (isDuplicate(goods, uniqueName.toString())) {
            log.warn("Failed to save, duplicate goods, " + goods.toString());
            throw new DuplicateException("exception.duplicate.goods");
        }
        goods.setUniqueName(uniqueName.toString());
        if (ValidatorHelper.isEmpty(goods.getId())) {
            if (ValidatorHelper.isEmpty(goods.getBrandId())) {
                throw new Exception("exception.required.brandId");
            } else if (ValidatorHelper.isEmpty(goods.getCategoryId())) {
                throw new Exception("exception.required.categoryId");
            } else if (ValidatorHelper.isEmpty(goods.getName())) {
                throw new Exception("exception.required.name");
            }
            goods.setId(PrimaryKeyCreator.create());
            goods.setOrderby(99);
            goods.setRecentlyUpdate(new Date());
            goods.setPinyin(StringHelper.toPinyin(goods.getName()));
            goodsDAO.create(goods);
        } else {
            goods.setRecentlyUpdate(new Date());
            goodsDAO.update(goods);
        }
        //
        if (propMap != null) {
            // 批量清除以前选中的属性值
            goodsPropValueDAO.removeByGoodsId(goods.getId());
            Set<String> keys = propMap.keySet();
            Iterator<String> it = keys.iterator();
            while (it.hasNext()) {
                String propId = it.next();
                String valId = propMap.get(propId);
                if (ValidatorHelper.isEmpty(valId)) {
                    continue;
                }
                PropValue val = propValueDAO.getById(valId);
                if (ValidatorHelper.isEmpty(val)) {
                    continue;
                }
                GoodsPropValue gval = new GoodsPropValue();
                gval.setGoodsId(goods.getId());
                gval.setPropValueId(val.getId());
                gval.setPropValueName(val.getName());
                gval.setId(PrimaryKeyCreator.create());
                goodsPropValueDAO.create(gval);
            }
        }
        //
        IndexObjectBufferPool.add(goods);
        //
        BrandCategoryRelation bcr = brandCategoryRelationDAO.getByBrandIdAndCategoryId(goods.getBrandId(), goods.getCategoryId());
        if (null == bcr) {
            bcr = new BrandCategoryRelation();
            bcr.setId(PrimaryKeyCreator.create());
            bcr.setBrandId(goods.getBrandId());
            bcr.setCategoryId(goods.getCategoryId());
            brandCategoryRelationDAO.create(bcr);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void saveCategory(Category category) {
        String pinyin = StringHelper.toPinyin(category.getName(), 1);
        String initial = StringHelper.getInitial(category.getName(), 1);
        String firstLetter = pinyin.substring(0, 1);
        if (pinyin != null) {
            category.setPinyin(pinyin);
            category.setInitial(initial);
            category.setFirstLetter(firstLetter);
        }
        if (ValidatorHelper.isEmpty(category.getId())) {
            category.setId(PrimaryKeyCreator.create());
            category.setOrderby(99);
            categoryDAO.create(category);
        } else {
            categoryDAO.update(category);
        }
        cache.del("category_all");
        cache.del("category_" + category.getId());
    }

    public List<Category> findAllCategory() {
        List<Category> list = (List<Category>) cache.get("category_all");
        if (ValidatorHelper.isEmpty(list)) {
            list = categoryDAO.findAll();
            cache.set("category_all", list);
        }
        return list;
    }

    public Category getCategoryById(String id) {
        Category c = (Category) cache.get("category_" + id);
        if (c == null) {
            c = categoryDAO.getById(id);
            cache.set("category_" + id, c);
        }
        return c;
    }

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
    public void saveBrand(Brand brand) {
        String pinyin = StringHelper.toPinyin(brand.getName(), 1);
        String initial = StringHelper.getInitial(brand.getName(), 1);
        String firstLetter = pinyin.substring(0, 1);
        if (pinyin != null) {
            brand.setPinyin(pinyin);
            brand.setInitial(initial);
            brand.setFirstLetter(firstLetter);
        }
        if (ValidatorHelper.isEmpty(brand.getId())) {
            brand.setId(PrimaryKeyCreator.create());
            brand.setOrderby(99);
            brandDAO.create(brand);
        } else {
            brandDAO.update(brand);
        }
        cache.del("brand_all");
        cache.del("brand_" + brand.getId());
    }

    public List<Brand> findAllBrand() {
        List<Brand> list = (List<Brand>) cache.get("brand_all");
        if (ValidatorHelper.isEmpty(list)) {
            list = brandDAO.findAll();
            cache.set("brand_all", list);
        }
        return list;
    }

    public List<Brand> findBrandByFirstLetter(String firstLetter
            , Pagination pagination) {
        pagination.setOrderList(new Pagination.Order[]{
                Pagination.getNewOrder("first_letter", Boolean.TRUE)
                // 指定按照首字母排序
        });
        return brandDAO.findAll(firstLetter, pagination);
    }

    public int countBrandByFirstLetter(String firstLetter) {
        return brandDAO.count(firstLetter);
    }

    public Brand getBrandById(String id) {
        Brand b = (Brand) cache.get("brand_" + id);
        if (b == null) {
            b = brandDAO.getById(id);
            cache.set("brand_" + id, b);
        }
        return b;
    }

    @Transactional(readOnly = false, rollbackFor = RuntimeException.class)
    public void updateGoodsIndexed(Goods goods) {
        goods.setRecentlyUpdate(new Date());
        goodsDAO.update(goods);
    }

    public List<Goods> findAllGoods(Pagination pagination) {
        return goodsDAO.findAll(pagination);
    }

    public Category getCategoryByName(String name) {
        return categoryDAO.getByName(name);
    }

    public Brand getBrandByName(String name) {
        return brandDAO.getByName(name);
    }

    /**
     * @param brandId
     * @param pagination TODO
     * @return
     */
    public List<Goods> findByBrandId(String brandId, Pagination pagination) {
        return goodsDAO.findByBrandId(brandId, pagination);
    }

    /**
     * @param categoryId
     * @param pagination TODO
     * @return
     */
    public List<Goods> findByCategoryId(String categoryId, Pagination pagination) {
        return goodsDAO.findByCategoryId(categoryId, pagination);
    }

    public int countCategoryByFirstLetter(String flt) {
        return categoryDAO.countByFirstLetter(flt);
    }

    public List<Category> findCategoryByFirstLetter(String flt,
                                                    Pagination pagination) {
        pagination.setOrderList(new Pagination.Order[]{
                Pagination.getNewOrder("first_letter", Boolean.TRUE)
                // 指定按照首字母排序
        });
        return categoryDAO.findByFirstLetter(flt, pagination);
    }

    /**
     * @param brandId
     * @param categoryId
     * @param pagination TODO
     * @return
     */
    public List<Goods> findByBrandIdAndCategoryId(String brandId,
                                                  String categoryId, Pagination pagination) {
        return goodsDAO.findByBrandIdAndCategoryId(brandId, categoryId, pagination);
    }

    public Integer countByBrandIdAndCategoryId(String brandId, String categoryId) {
        return goodsDAO.countByBrandIdAndCategoryId(brandId, categoryId);
    }

    public Integer countByCategoryId(String categoryId) {
        return goodsDAO.countByCategoryId(categoryId);
    }

    public Integer countByBrandId(String brandId) {
        return goodsDAO.countByBrandId(brandId);
    }

    public List<Goods> findAll(Pagination pagination) {
        return goodsDAO.findAll(pagination);
    }

    public List<Goods> findAllNotIndexed(Pagination pagination) {
        return goodsDAO.findAllNotIndexed(pagination);
    }

    public Integer countAll() {
        return goodsDAO.countAll();
    }

    public int countAllNotIndexed() {
        return goodsDAO.countAllNotIndexed();
    }

    public Goods getGoodsById(String id) {
        return goodsDAO.getById(id);
    }

    public List<PropValue> findPropValues(String propId) {
        return propValueDAO.findPropValues(propId);
    }

    public void savePropValue(String propId, String name) {
        PropValue pv = propValueDAO.getByPropIdAndName(propId, name);
        if (pv != null) {
            return;
        }
        pv = new PropValue();
        pv.setId(PrimaryKeyCreator.create());
        pv.setPropId(propId);
        pv.setName(name);
        propValueDAO.create(pv);
    }

    public void savePropValue(PropValue v) throws Exception {
        if (ValidatorHelper.isEmpty(v.getPropId())) {
            throw new Exception("remind.illegal.parameters");
        } else if (ValidatorHelper.isEmpty(v.getName())) {
            throw new Exception("remind.required.name");
        }
        if (ValidatorHelper.isEmpty(v.getId())) {
            v.setId(PrimaryKeyCreator.create());
            propValueDAO.create(v);
        } else {
            propValueDAO.update(v);
            GoodsPropValue gpv = goodsPropValueDAO.getById(v.getId());
            if (gpv != null) {
                gpv.setPropValueName(v.getName());
                goodsPropValueDAO.update(gpv);
            }
        }
    }

    public PropValue getPropValue(String id) {
        return propValueDAO.getById(id);
    }

    public void removePropValueById(String id) {
        propValueDAO.remove(propValueDAO.getById(id));
    }

    public List<GoodsPropValue> findGoodsPropValueByGoodsId(String goodsId) {
        return goodsPropValueDAO.findByGoodsId(goodsId);
    }

    @Autowired
    private BrandCategoryRelationDAO brandCategoryRelationDAO;

    @Autowired
    private GoodsPropValueDAO goodsPropValueDAO;

    @Autowired
    private PropertiesDAO propertiesDAO;

    @Autowired
    private PropValueDAO propValueDAO;

    @Autowired
    private CategoryDAO categoryDAO;

    @Autowired
    private GoodsDAO goodsDAO;

    @Autowired
    private BrandDAO brandDAO;


}
